home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / oleo-1_4.lha / oleo-1.4 / _doprnt.c next >
C/C++ Source or Header  |  1993-05-07  |  17KB  |  718 lines

  1. /*
  2.  * Copyright (c) 1988 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #if defined(LIBC_SCCS) && !defined(lint)
  19. static char sccsid[] = "@(#)doprnt.c    5.35 (Berkeley) 6/27/88";
  20. #endif /* LIBC_SCCS and not lint */
  21.  
  22. #include <sys/types.h>
  23. #include <varargs.h>
  24. #include <stdio.h>
  25. #include <ctype.h>
  26.  
  27. #ifdef SYSV
  28. typedef unsigned char u_char;
  29. typedef unsigned long u_long;
  30. #endif
  31.  
  32. /* 11-bit exponent (VAX G floating point) is 308 decimal digits */
  33. #define    MAXEXP        308
  34. /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
  35. #define    MAXFRACT    39
  36.  
  37. #define    DEFPREC        6
  38.  
  39. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  40.  
  41. #define    PUTC(ch)    (void) putc(ch, fp)
  42.  
  43. #define    ARG() \
  44.     _ulong = flags&LONGINT ? va_arg(argp, long) : \
  45.         flags&SHORTINT ? va_arg(argp, short) : va_arg(argp, int);
  46.  
  47. #define    todigit(c)    ((c) - '0')
  48. #define    tochar(n)    ((n) + '0')
  49.  
  50. /* have to deal with the negative buffer count kludge */
  51. #define    NEGATIVE_COUNT_KLUDGE
  52.  
  53. #define    LONGINT        0x01        /* long integer */
  54. #define    LONGDBL        0x02        /* long double; unimplemented */
  55. #define    SHORTINT    0x04        /* short integer */
  56. #define    ALT        0x08        /* alternate form */
  57. #define    LADJUST        0x10        /* left adjustment */
  58. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  59. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  60.  
  61. extern double __plinf, __neinf, __nan;
  62. /* double __plinf = 1e500; */
  63. char *__inf_str = "#INF";
  64.  
  65. /* double __neinf = -1e500; */
  66. char *__ninf_str = "#NINF";
  67.  
  68. /* __asm(".globl ___nan");
  69. __asm("___nan: .double 0rnan"); */
  70. /* double __nan = __asm("0rnan"); */
  71. char *__nan_str = "#NAN";
  72.  
  73. static int cvt();
  74. static char *round();
  75. static char *exponent();
  76.  
  77. extern double modf();
  78. extern int strlen();
  79. extern void bcopy();
  80.  
  81. int
  82. _doprnt(fmt0, argp, fp)
  83.     u_char *fmt0;
  84.     va_list argp;
  85.     register FILE *fp;
  86. {
  87.     register u_char *fmt;    /* format string */
  88.     register int ch;    /* character from fmt */
  89.     register int cnt;    /* return value accumulator */
  90.     register int n;        /* random handy integer */
  91.     register char *t;    /* buffer pointer */
  92.     double _double;        /* double precision arguments %[eEfgG] */
  93.     u_long _ulong;        /* integer arguments %[diouxX] */
  94.     int base;        /* base for [diouxX] conversion */
  95.     int dprec;        /* decimal precision in [diouxX] */
  96.     int fieldsz;        /* field size expanded by sign, etc */
  97.     int flags;        /* flags as above */
  98.     int fpprec;        /* `extra' floating precision in [eEfgG] */
  99.     int prec;        /* precision from format (%.3d), or -1 */
  100.     int realsz;        /* field size expanded by decimal precision */
  101.     int size;        /* size of converted field or string */
  102.     int width;        /* width from format (%8d), or 0 */
  103.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  104.     char softsign;        /* temporary negative sign for floats */
  105.     char *digs;        /* digits for [diouxX] conversion */
  106.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  107.  
  108.     if (fp->_flag & _IORW) {
  109.         fp->_flag |= _IOWRT;
  110.         fp->_flag &= ~(_IOEOF|_IOREAD);
  111.     }
  112.     if ((fp->_flag & _IOWRT) == 0)
  113.         return (EOF);
  114.  
  115.     fmt = fmt0;
  116.     digs = "0123456789abcdef";
  117.     for (cnt = 0;; ++fmt) {
  118.         n = fp->_cnt;
  119.         for (t = (char *)fp->_ptr; (ch = *fmt) && ch != '%';
  120.              ++cnt, ++fmt)
  121.             if (--n < 0
  122. #ifdef NEGATIVE_COUNT_KLUDGE
  123. #ifdef _bufsiz
  124.                             && (!(fp->_flag & _IOLBF) || -n >= _bufsiz(fp))
  125. #else  /* ndef _bufsize: */
  126.                             && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz)
  127. #endif /* ndef _bufsize */
  128. #endif
  129.                 || ch == '\n' && fp->_flag & _IOLBF) {
  130.                 fp->_cnt = n;
  131.                 fp->_ptr = t;
  132.                 (void) _flsbuf((u_char)ch, fp);
  133.                 n = fp->_cnt;
  134.                 t = (char *)fp->_ptr;
  135.             } else
  136.                 *t++ = ch;
  137.         fp->_cnt = n;
  138.         fp->_ptr = t;
  139.         if (!ch)
  140.             return (cnt);
  141.  
  142.         flags = 0; dprec = 0; fpprec = 0; width = 0;
  143.         prec = -1;
  144.         sign = '\0';
  145.  
  146. rflag:        switch (*++fmt) {
  147.         case ' ':
  148.             /*
  149.              * ``If the space and + flags both appear, the space
  150.              * flag will be ignored.''
  151.              *    -- ANSI X3J11
  152.              */
  153.             if (!sign)
  154.                 sign = ' ';
  155.             goto rflag;
  156.         case '#':
  157.             flags |= ALT;
  158.             goto rflag;
  159.         case '*':
  160.             /*
  161.              * ``A negative field width argument is taken as a
  162.              * - flag followed by a  positive field width.''
  163.              *    -- ANSI X3J11
  164.              * They don't exclude field widths read from args.
  165.              */
  166.             if ((width = va_arg(argp, int)) >= 0)
  167.                 goto rflag;
  168.             width = -width;
  169.             /* FALLTHROUGH */
  170.         case '-':
  171.             flags |= LADJUST;
  172.             goto rflag;
  173.         case '+':
  174.             sign = '+';
  175.             goto rflag;
  176.         case '.':
  177.             if (*++fmt == '*')
  178.                 n = va_arg(argp, int);
  179.             else {
  180.                 n = 0;
  181.                 while (isascii(*fmt) && isdigit(*fmt))
  182.                     n = 10 * n + todigit(*fmt++);
  183.                 --fmt;
  184.             }
  185.             prec = n < 0 ? -1 : n;
  186.             goto rflag;
  187.         case '0':
  188.             /*
  189.              * ``Note that 0 is taken as a flag, not as the
  190.              * beginning of a field width.''
  191.              *    -- ANSI X3J11
  192.              */
  193.             flags |= ZEROPAD;
  194.             goto rflag;
  195.         case '1': case '2': case '3': case '4':
  196.         case '5': case '6': case '7': case '8': case '9':
  197.             n = 0;
  198.             do {
  199.                 n = 10 * n + todigit(*fmt);
  200.             } while (isascii(*++fmt) && isdigit(*fmt));
  201.             width = n;
  202.             --fmt;
  203.             goto rflag;
  204.         case 'L':
  205.             flags |= LONGDBL;
  206.             goto rflag;
  207.         case 'h':
  208.             flags |= SHORTINT;
  209.             goto rflag;
  210.         case 'l':
  211.             flags |= LONGINT;
  212.             goto rflag;
  213.         case 'c':
  214.             *(t = buf) = va_arg(argp, int);
  215.             size = 1;
  216.             sign = '\0';
  217.             goto pforw;
  218.         case 'D':
  219.             flags |= LONGINT;
  220.             /*FALLTHROUGH*/
  221.         case 'd':
  222.         case 'i':
  223.             ARG();
  224.             if ((long)_ulong < 0) {
  225.                 _ulong = -_ulong;
  226.                 sign = '-';
  227.             }
  228.             base = 10;
  229.             goto number;
  230.         case 'e':
  231.         case 'E':
  232.         case 'f':
  233.         case 'g':
  234.         case 'G':
  235.             _double = va_arg(argp, double);
  236.             /*
  237.              * don't do unrealistic precision; just pad it with
  238.              * zeroes later, so buffer size stays rational.
  239.              */
  240.             if (prec > MAXFRACT) {
  241.                 if (*fmt != 'g' && *fmt != 'G' || (flags&ALT))
  242.                     fpprec = prec - MAXFRACT;
  243.                 prec = MAXFRACT;
  244.             }
  245.             else if (prec == -1)
  246.                 prec = DEFPREC;
  247.             /*
  248.              * softsign avoids negative 0 if _double is < 0 and
  249.              * no significant digits will be shown
  250.              */
  251.             if (_double < 0) {
  252.                 softsign = '-';
  253.                 _double = -_double;
  254.             }
  255.             else
  256.                 softsign = 0;
  257.             /*
  258.              * cvt may have to round up past the "start" of the
  259.              * buffer, i.e. ``intf("%.2f", (double)9.999);'';
  260.              * if the first char isn't NULL, it did.
  261.              */
  262.             *buf = NULL;
  263.             size = cvt(_double, prec, flags, &softsign, *fmt, buf,
  264.                 buf + sizeof(buf));
  265.             if (softsign)
  266.                 sign = '-';
  267.             t = *buf ? buf : buf + 1;
  268.             goto pforw;
  269.         case 'n':
  270.             if (flags & LONGINT)
  271.                 *va_arg(argp, long *) = cnt;
  272.             else if (flags & SHORTINT)
  273.                 *va_arg(argp, short *) = cnt;
  274.             else
  275.                 *va_arg(argp, int *) = cnt;
  276.             break;
  277.         case 'O':
  278.             flags |= LONGINT;
  279.             /*FALLTHROUGH*/
  280.         case 'o':
  281.             ARG();
  282.             base = 8;
  283.             goto nosign;
  284.         case 'p':
  285.             /*
  286.              * ``The argument shall be a pointer to void.  The
  287.              * value of the pointer is converted to a sequence
  288.              * of printable characters, in an implementation-
  289.              * defined manner.''
  290.              *    -- ANSI X3J11
  291.              */
  292.             /* NOSTRICT */
  293.             _ulong = (u_long)va_arg(argp, void *);
  294.             base = 16;
  295.             goto nosign;
  296.         case 's':
  297.             if (!(t = va_arg(argp, char *)))
  298.                 t = "(null)";
  299.             if (prec >= 0) {
  300.                 /*
  301.                  * can't use strlen; can only look for the
  302.                  * NUL in the first `prec' characters, and
  303.                  * strlen() will go further.
  304.                  */
  305.                 char *p, *memchr();
  306.  
  307.                 if (p = memchr(t, 0, prec)) {
  308.                     size = p - t;
  309.                     if (size > prec)
  310.                         size = prec;
  311.                 } else
  312.                     size = prec;
  313.             } else
  314.                 size = strlen(t);
  315.             sign = '\0';
  316.             goto pforw;
  317.         case 'U':
  318.             flags |= LONGINT;
  319.             /*FALLTHROUGH*/
  320.         case 'u':
  321.             ARG();
  322.             base = 10;
  323.             goto nosign;
  324.         case 'X':
  325.             digs = "0123456789ABCDEF";
  326.             /* FALLTHROUGH */
  327.         case 'x':
  328.             ARG();
  329.             base = 16;
  330.             /* leading 0x/X only if non-zero */
  331.             if (flags & ALT && _ulong != 0)
  332.                 flags |= HEXPREFIX;
  333.  
  334.             /* unsigned conversions */
  335. nosign:            sign = '\0';
  336.             /*
  337.              * ``... diouXx conversions ... if a precision is
  338.              * specified, the 0 flag will be ignored.''
  339.              *    -- ANSI X3J11
  340.              */
  341. number:            if ((dprec = prec) >= 0)
  342.                 flags &= ~ZEROPAD;
  343.  
  344.             /*
  345.              * ``The result of converting a zero value with an
  346.              * explicit precision of zero is no characters.''
  347.              *    -- ANSI X3J11
  348.              */
  349.             t = buf + BUF;
  350.             if (_ulong != 0 || prec != 0) {
  351.                 do {
  352.                     *--t = digs[_ulong % base];
  353.                     _ulong /= base;
  354.                 } while (_ulong);
  355.                 digs = "0123456789abcdef";
  356.                 if (flags & ALT && base == 8 && *t != '0')
  357.                     *--t = '0'; /* octal leading 0 */
  358.             }
  359.             size = buf + BUF - t;
  360.  
  361. pforw:
  362.             /*
  363.              * All reasonable formats wind up here.  At this point,
  364.              * `t' points to a string which (if not flags&LADJUST)
  365.              * should be padded out to `width' places.  If
  366.              * flags&ZEROPAD, it should first be prefixed by any
  367.              * sign or other prefix; otherwise, it should be blank
  368.              * padded before the prefix is emitted.  After any
  369.              * left-hand padding and prefixing, emit zeroes
  370.              * required by a decimal [diouxX] precision, then print
  371.              * the string proper, then emit zeroes required by any
  372.              * leftover floating precision; finally, if LADJUST,
  373.              * pad with blanks.
  374.              */
  375.  
  376.             /*
  377.              * compute actual size, so we know how much to pad
  378.              * fieldsz excludes decimal prec; realsz includes it
  379.              */
  380.             fieldsz = size + fpprec;
  381.             if (sign)
  382.                 fieldsz++;
  383.             if (flags & HEXPREFIX)
  384.                 fieldsz += 2;
  385.             realsz = dprec > fieldsz ? dprec : fieldsz;
  386.  
  387.             /* right-adjusting blank padding */
  388.             if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
  389.                 for (n = realsz; n < width; n++)
  390.                     PUTC(' ');
  391.             /* prefix */
  392.             if (sign)
  393.                 PUTC(sign);
  394.             if (flags & HEXPREFIX) {
  395.                 PUTC('0');
  396.                 PUTC((char)*fmt);
  397.             }
  398.             /* right-adjusting zero padding */
  399.             if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  400.                 for (n = realsz; n < width; n++)
  401.                     PUTC('0');
  402.             /* leading zeroes from decimal precision */
  403.             for (n = fieldsz; n < dprec; n++)
  404.                 PUTC('0');
  405.  
  406.             /* the string or number proper */
  407.             if (fp->_cnt - (n = size) >= 0 &&
  408.                 (fp->_flag & _IOLBF) == 0) {
  409.                 fp->_cnt -= n;
  410.                 bcopy(t, (char *)fp->_ptr, n);
  411.                 fp->_ptr += n;
  412.             } else
  413.                 while (--n >= 0)
  414.                     PUTC(*t++);
  415.             /* trailing f.p. zeroes */
  416.             while (--fpprec >= 0)
  417.                 PUTC('0');
  418.             /* left-adjusting padding (always blank) */
  419.             if (flags & LADJUST)
  420.                 for (n = realsz; n < width; n++)
  421.                     PUTC(' ');
  422.             /* finally, adjust cnt */
  423.             cnt += width > realsz ? width : realsz;
  424.             break;
  425.         case '\0':    /* "%?" prints ?, unless ? is NULL */
  426.             return (cnt);
  427.         default:
  428.             PUTC((char)*fmt);
  429.             cnt++;
  430.         }
  431.     }
  432.     /* NOTREACHED */
  433. }
  434.  
  435. static int
  436. cvt(number, prec, flags, signp, fmtch, startp, endp)
  437.     double number;
  438.     register int prec;
  439.     int flags;
  440.     u_char fmtch;
  441.     char *signp, *startp, *endp;
  442. {
  443.     register char *p, *t;
  444.     register double fract;
  445.     int dotrim, expcnt, gformat;
  446.     double integer, tmp, modf();
  447.  
  448.     /* JF for numbers */
  449.     if(number!=number) {
  450.         t= ++startp;
  451.         p=__nan_str;
  452.         while(*p)
  453.             *t++= *p++;
  454.         return t-startp;
  455.     }
  456.     if(number==__plinf) {
  457.         t= ++startp;
  458.         p= (*signp) ? __ninf_str : __inf_str;
  459.         *signp=0;
  460.         while(*p)
  461.             *t++= *p++;
  462.         return t-startp;
  463.     }
  464.     /* if(number==__neinf) {
  465.         t= ++startp;
  466.         p=__ninf_str;
  467.         while(*p)
  468.             *t++= *p++;
  469.         return t-startp;
  470.     } */
  471.     dotrim = expcnt = gformat = 0;
  472.     fract = modf(number, &integer);
  473.  
  474.     /* get an extra slot for rounding. */
  475.     t = ++startp;
  476.  
  477.     /*
  478.      * get integer portion of number; put into the end of the buffer; the
  479.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  480.      */
  481.     for (p = endp - 1; integer; ++expcnt) {
  482.         tmp = modf(integer / 10, &integer);
  483.         *p-- = tochar((int)((tmp + .01) * 10));
  484.     }
  485.     switch(fmtch) {
  486.     case 'f':
  487.         /* reverse integer into beginning of buffer */
  488.         if (expcnt)
  489.             for (; ++p < endp; *t++ = *p);
  490.         else
  491.             *t++ = '0';
  492.         /*
  493.          * if precision required or alternate flag set, add in a
  494.          * decimal point.
  495.          */
  496.         if (prec || flags&ALT)
  497.             *t++ = '.';
  498.         /* if requires more precision and some fraction left */
  499.         if (fract) {
  500.             if (prec)
  501.                 do {
  502.                     fract = modf(fract * 10, &tmp);
  503.                     *t++ = tochar((int)tmp);
  504.                 } while (--prec && fract);
  505.             if (fract)
  506.                 startp = round(fract, (int *)NULL, startp,
  507.                     t - 1, (char)0, signp);
  508.         }
  509.         for (; prec--; *t++ = '0');
  510.         break;
  511.     case 'e':
  512.     case 'E':
  513. eformat:    if (expcnt) {
  514.             *t++ = *++p;
  515.             if (prec || flags&ALT)
  516.                 *t++ = '.';
  517.             /* if requires more precision and some integer left */
  518.             for (; prec && ++p < endp; --prec)
  519.                 *t++ = *p;
  520.             /*
  521.              * if done precision and more of the integer component,
  522.              * round using it; adjust fract so we don't re-round
  523.              * later.
  524.              */
  525.             if (!prec && ++p < endp) {
  526.                 fract = 0;
  527.                 startp = round((double)0, &expcnt, startp,
  528.                     t - 1, *p, signp);
  529.             }
  530.             /* adjust expcnt for digit in front of decimal */
  531.             --expcnt;
  532.         }
  533.         /* until first fractional digit, decrement exponent */
  534.         else if (fract) {
  535.             /* adjust expcnt for digit in front of decimal */
  536.             for (expcnt = -1;; --expcnt) {
  537.                 fract = modf(fract * 10, &tmp);
  538.                 if (tmp)
  539.                     break;
  540.             }
  541.             *t++ = tochar((int)tmp);
  542.             if (prec || flags&ALT)
  543.                 *t++ = '.';
  544.         }
  545.         else {
  546.             *t++ = '0';
  547.             if (prec || flags&ALT)
  548.                 *t++ = '.';
  549.         }
  550.         /* if requires more precision and some fraction left */
  551.         if (fract) {
  552.             if (prec)
  553.                 do {
  554.                     fract = modf(fract * 10, &tmp);
  555.                     *t++ = tochar((int)tmp);
  556.                 } while (--prec && fract);
  557.             if (fract)
  558.                 startp = round(fract, &expcnt, startp,
  559.                     t - 1, (char)0, signp);
  560.         }
  561.         /* if requires more precision */
  562.         for (; prec--; *t++ = '0');
  563.  
  564.         /* unless alternate flag, trim any g/G format trailing 0's */
  565.         if (gformat && !(flags&ALT)) {
  566.             while (t > startp && *--t == '0');
  567.             if (*t == '.')
  568.                 --t;
  569.             ++t;
  570.         }
  571.         t = exponent(t, expcnt, fmtch);
  572.         break;
  573.     case 'g':
  574.     case 'G':
  575.         /* a precision of 0 is treated as a precision of 1. */
  576.         if (!prec)
  577.             ++prec;
  578.         /*
  579.          * ``The style used depends on the value converted; style e
  580.          * will be used only if the exponent resulting from the
  581.          * conversion is less than -4 or greater than the precision.''
  582.          *    -- ANSI X3J11
  583.          */
  584.         if (expcnt > prec || !expcnt && fract && fract < .0001) {
  585.             /*
  586.              * g/G format counts "significant digits, not digits of
  587.              * precision; for the e/E format, this just causes an
  588.              * off-by-one problem, i.e. g/G considers the digit
  589.              * before the decimal point significant and e/E doesn't
  590.              * count it as precision.
  591.              */
  592.             --prec;
  593.             fmtch -= 2;        /* G->E, g->e */
  594.             gformat = 1;
  595.             goto eformat;
  596.         }
  597.         /*
  598.          * reverse integer into beginning of buffer,
  599.          * note, decrement precision
  600.          */
  601.         if (expcnt)
  602.             for (; ++p < endp; *t++ = *p, --prec);
  603.         else
  604.             *t++ = '0';
  605.         /*
  606.          * if precision required or alternate flag set, add in a
  607.          * decimal point.  If no digits yet, add in leading 0.
  608.          */
  609.         if (prec || flags&ALT) {
  610.             dotrim = 1;
  611.             *t++ = '.';
  612.         }
  613.         else
  614.             dotrim = 0;
  615.         /* if requires more precision and some fraction left */
  616.         if (fract) {
  617.             if (prec) {
  618.                 do {
  619.                     fract = modf(fract * 10, &tmp);
  620.                     *t++ = tochar((int)tmp);
  621.                 } while(!tmp);
  622.                 while (--prec && fract) {
  623.                     fract = modf(fract * 10, &tmp);
  624.                     *t++ = tochar((int)tmp);
  625.                 }
  626.             }
  627.             if (fract)
  628.                 startp = round(fract, (int *)NULL, startp,
  629.                     t - 1, (char)0, signp);
  630.         }
  631.         /* alternate format, adds 0's for precision, else trim 0's */
  632.         if (flags&ALT)
  633.             for (; prec--; *t++ = '0');
  634.         else if (dotrim) {
  635.             while (t > startp && *--t == '0');
  636.             if (*t != '.')
  637.                 ++t;
  638.         }
  639.     }
  640.     return(t - startp);
  641. }
  642.  
  643. static char *
  644. round(fract, exp, start, end, ch, signp)
  645.     double fract;
  646.     int *exp;
  647.     register char *start, *end;
  648.     char ch, *signp;
  649. {
  650.     double tmp;
  651.  
  652.     if (fract)
  653.         (void)modf(fract * 10, &tmp);
  654.     else
  655.         tmp = todigit(ch);
  656.     if (tmp > 4)
  657.         for (;; --end) {
  658.             if (*end == '.')
  659.                 --end;
  660.             if (++*end <= '9')
  661.                 break;
  662.             *end = '0';
  663.             if (end == start) {
  664.                 if (exp) {    /* e/E; increment exponent */
  665.                     *end = '1';
  666.                     ++*exp;
  667.                 }
  668.                 else {        /* f; add extra digit */
  669.                     *--end = '1';
  670.                     --start;
  671.                 }
  672.                 break;
  673.             }
  674.         }
  675.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  676.     else if (*signp == '-')
  677.         for (;; --end) {
  678.             if (*end == '.')
  679.                 --end;
  680.             if (*end != '0')
  681.                 break;
  682.             if (end == start)
  683.                 *signp = 0;
  684.         }
  685.     return(start);
  686. }
  687.  
  688. static char *
  689. exponent(p, exp, fmtch)
  690.     register char *p;
  691.     register int exp;
  692.     u_char fmtch;
  693. {
  694.     register char *t;
  695.     char expbuf[MAXEXP];
  696.  
  697.     *p++ = fmtch;
  698.     if (exp < 0) {
  699.         exp = -exp;
  700.         *p++ = '-';
  701.     }
  702.     else
  703.         *p++ = '+';
  704.     t = expbuf + MAXEXP;
  705.     if (exp > 9) {
  706.         do {
  707.             *--t = tochar(exp % 10);
  708.         } while ((exp /= 10) > 9);
  709.         *--t = tochar(exp);
  710.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  711.     }
  712.     else {
  713.         *p++ = '0';
  714.         *p++ = tochar(exp);
  715.     }
  716.     return(p);
  717. }
  718.